package top.ieei.demo.tftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Locale;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * 处理TFTP读写请求<br>
 * @author xiecongshu
 */
public class RequestHandler
{
    /**
     * 日志
     */
    private static final Log LOG = LogFactory.getLog(RequestHandler.class);
    
    /**
     * 客户端处理程序
     */
    private ClientHandler tftpClient;
    
    /**
     * <默认构造函数>
     */
    public RequestHandler() throws SocketException
    {
        tftpClient = new ClientHandler();
    }
    
    /**
     * 检查此客户端处理程序是否还在处理之前的读写请求，如果没有，返回true表示空闲，等待新的请求
     * @return boolean
     */
    public boolean isIdle()
    {
        return tftpClient.waitingForNewRequest();
    }
    
    /**
     * 处理读写请求
     * @param request
     * @param clientAddress
     * @param clientPort void
     */
    public void handleRequests(TftpRequest request, InetAddress clientAddress,
            int clientPort)
    {
        if (request == null)
        {
            LOG.error("RequestHandler.handleRequests got a null packet!");
            return;
        }
        if (clientAddress == null)
        {
            LOG.error("RequestHandler.handleRequests got a invalid client address!");
            return;
        }
        if (clientPort == 0)
        {
            LOG.error("RequestHandler.handleRequests got a invalid client port!");
            return;
        }
        
        // 连接新的客户端，准备发送TFTP数据
        tftpClient.connect(clientAddress, clientPort);
        
        // 取TFTP选项中的超时时间，如果没有设置，设置默认的5秒
        int timeout = request.getTimeout();
        if (timeout <= 0)
        {
            timeout = 5000;
        }
        tftpClient.setTimeout(timeout);
        
        // 如果是读文件请求（下载文件）
        if (request instanceof ReadRequest)
        {
            ReadRequest rr = (ReadRequest) request;
            boolean sendOK = false;
            LOG.info(tftpClient.getClientInfo() + "read request for file:"
                    + rr.getFileName());
            InputStream is = null;
            try
            {
                String fileName = getFimeName(rr.getFileName());
                is = new FileInputStream(new File(TftpServer.tftpRoot
                        + fileName));
                sendOK = tftpClient.downloadFile(is,
                        clientAddress,
                        clientPort,
                        rr);
                if (sendOK)
                {
                    LOG.info(tftpClient.getClientInfo()
                            + "download file success. File:" + fileName);
                }
                else
                {
                    LOG.info(tftpClient.getClientInfo()
                            + "download file fail. File:" + fileName);
                }
            }
            catch (FileNotFoundException e)
            {
                LOG.error(tftpClient.getClientInfo()
                        + "download file error,file not found. File:"
                        + rr.getFileName());
                tftpClient.sendErrorPacket(TftpError.ERROR_FILE_NOT_FOUND,
                        "File not found. File:" + rr.getFileName());
                return;
            }
            finally
            {
                if (null != is)
                {
                    try
                    {
                        is.close();
                    }
                    catch (IOException e)
                    {
                        LOG.error("Close the inputStream for download file error.file:"
                                + rr.getFileName());
                        return;
                    }
                }
            }
        }
        else if (request instanceof WriteRequest)
        {
            WriteRequest wr = (WriteRequest) request;
            LOG.info(tftpClient.getClientInfo() + "write request for file:"
                    + wr.getFileName());
            OutputStream os = null;
            try
            {
                String fileName = getFimeName(wr.getFileName());
                os = new FileOutputStream(TftpServer.tftpRoot + fileName);
                boolean receiveOK = tftpClient.uploadFile(os,
                        clientAddress,
                        clientPort,
                        wr);
                if (receiveOK)
                {
                    LOG.info(tftpClient.getClientInfo()
                            + "upload file success. File:" + fileName);
                }
                else
                {
                    LOG.info(tftpClient.getClientInfo()
                            + "upload file fail. File:" + fileName);
                }
            }
            catch (Exception e)
            {
                LOG.error(tftpClient.getClientInfo()
                        + "download file error. " + e.getMessage() + " File:"
                        + wr.getFileName());
            }
            finally
            {
                if (null != os)
                {
                    try
                    {
                        os.close();
                    }
                    catch (IOException e)
                    {
                        LOG.error("Close the outputStream for upload file error. File:"
                                + wr.getFileName());
                    }
                }
            }
        }
    }
    
    /**
     * 文件目录分割符替换，linux下对windows文件分割符的修正
     * @param fname
     * @return String
     */
    public String getFimeName(String fname)
    {
        String osName = System.getProperty("os.name");
        if (!osName.toUpperCase(Locale.ENGLISH).startsWith("WIN"))
        {
            fname = fname.replaceAll("\\\\", "/");
            if (fname.indexOf('/') == 0)
            {
                fname = fname.substring(1, fname.length());
            }
        }
        else if (fname.indexOf('\\') == 0)
        {
            fname = fname.substring(1, fname.length());
        }
        return fname;
    }
    
    /**
     * 关闭客户端处理程序
     */
    public void stop()
    {
        tftpClient.disconnect();
    }
}
